{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Hardware Crypto Attack - NOT CURRENTLY AVAILABLE\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "So far we have mostly been talking about software crypto. But how can we expand this to hardware crypto? Luckily it takes very few changes, so you don't have much to do!\n",
    "\n",
    "In this lab we'll be looking at what is required to attack a hardware crypto device, and what sort of attacks work on these devices. In this case we're going to \"cheat\" and use an already recorded power trace, since we don't have hardware crypto on our target boards."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Capture"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "cd ../hardware/victims/firmware/\n",
    "mkdir -p simpleserial-aes-lab1 && cp -r simpleserial-aes/* $_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "cd ../hardware/victims/firmware/simpleserial-aes-lab1\n",
    "make PLATFORM=CW308_STM32F4 CRYPTO_TARGET=HWAES"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import chipwhisperer as cw\n",
    "scope = cw.scope()\n",
    "target = cw.target(scope)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%run \"Helper_Scripts/Setup_Target_Generic.ipynb\"\n",
    "\n",
    "\n",
    "scope.adc.samples = 2000\n",
    "scope.gain.mode = \"low\"\n",
    "scope"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "prog = cw.programmers.STM32FProgrammer\n",
    "fw_path = \"../hardware/victims/firmware/simpleserial-aes-lab1/simpleserial-aes-CW308_STM32F4.hex\"\n",
    "cw.programTarget(scope, prog, fw_path)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "project = cw.createProject(\"stm32f415_lab.cwp\", overwrite=True)\n",
    "tc = project.newSegment()\n",
    "\n",
    "#Capture Traces\n",
    "from tqdm import tqdm\n",
    "import numpy as np\n",
    "import time\n",
    "\n",
    "ktp = cw.ktp.Basic(target=target)\n",
    "\n",
    "N = 5000  # Number of traces\n",
    "target.init()\n",
    "for i in tqdm(range(N), desc='Capturing traces'):\n",
    "    # run aux stuff that should come before trace here\n",
    "\n",
    "    key, text = ktp.newPair()  # manual creation of a key, text pair can be substituted here\n",
    "\n",
    "    target.loadEncryptionKey(key)\n",
    "    target.loadInput(text)\n",
    "\n",
    "    # run aux stuff that should run before the scope arms here\n",
    "\n",
    "    scope.arm()\n",
    "\n",
    "    # run aux stuff that should run after the scope arms here\n",
    "\n",
    "    target.go()\n",
    "    timeout = 50\n",
    "    # wait for target to finish\n",
    "    while target.isDone() is False and timeout:\n",
    "        timeout -= 1\n",
    "        time.sleep(0.01)\n",
    "\n",
    "    try:\n",
    "        ret = scope.capture()\n",
    "        if ret:\n",
    "            print('Timeout happened during acquisition')\n",
    "    except IOError as e:\n",
    "        print('IOError: %s' % str(e))\n",
    "\n",
    "    # run aux stuff that should happen after trace here\n",
    "    \n",
    "    # note you may want:\n",
    "    # num_char = target.ser.inWaiting()\n",
    "    # response = target.ser.read(num_char)\n",
    "    textout = target.readOutput()  # clears the response from the serial port\n",
    "    #traces.append(scope.getLastTrace())\n",
    "    tc.addTrace(scope.getLastTrace(), text, textout, key)\n",
    "    \n",
    "project.appendSegment(tc)\n",
    "project.save()\n",
    "\n",
    "# cleanup the connection to the target and scope\n",
    "scope.dis()\n",
    "target.dis()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Analysis"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we'll add our traces to a preprocessing module. We can feed `project.traceManager()` right into `attack.setTraceSource()`, but we could also add pre-processing inbetween (more about this later). We'll also re-open the traces, in this case it is required since the call to `closeAll()` would have flushed the buffers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Force reload of project data (if you comment out 'closeAll()' this isn't needed)\n",
    "\n",
    "#We also rebuild the project object in case you only want to run this half\n",
    "project = cw.openProject('./stm32f415_lab.cwp')\n",
    "\n",
    "tm = project.traceManager()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This time we're going to do a few things. First we will get the traces, and plot a few of them as-is. You can adjust the traces plotted by adjusting the `range(10)`. For example `range(1)` plots the first trace."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from bokeh.plotting import figure, show\n",
    "from bokeh.io import output_notebook\n",
    "from bokeh.palettes import Dark2_5 as palette\n",
    "import itertools  \n",
    "\n",
    "output_notebook()\n",
    "p = figure(sizing_mode='scale_width', plot_height=300)\n",
    "\n",
    "# create a color iterator\n",
    "colors = itertools.cycle(palette)  \n",
    "\n",
    "x_range = range(0, tm.numPoints())\n",
    "for i, color in zip(range(10), colors): #Adjust range(n) to plot certain traces\n",
    "    p.line(x_range, tm.getTrace(i), color=color)\n",
    "show(p)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If this all works - let's just continue the attack! We're going to use the same leakge model as previously (Hamming weight), we'll seperate this out since will be changing that model around shortly."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "leak_model = cw.AES128(cw.AES128Leakage.SBox_output)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "attack = cw.CPA(project.traceManager(), leak_model)\n",
    "attack.setReportingInterval(50)\n",
    "attack.setPointRange((1312, 1317))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And then actually run it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cb = cw.getJupyterCallback(attack)\n",
    "attack_results = attack.processTracesNoGUI(cb, show_progress_bar=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This will almost certainly fail. The leakage model is incorrect, so we need to find the correct (new) leakage model we should be using. This turns out to be pretty easy, since most typical hardware implementations use only one of a few possible models. We'll specifically just try the \"Last Round State Over-Written\" model first. You can do this by updating the model above to have the following:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "leak_model = cw.AES128(cw.AES128Leakage.LastroundStateDiff)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "But this might not be enough! You may need to \"window\" around the area of interest. This is best done by plotting the results, and picking a nice area. For example a window of `attack.setPointRange((1312, 1314))` seems to work well on some traces."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from bokeh.plotting import figure, show\n",
    "from bokeh.io import output_notebook\n",
    "\n",
    "output_notebook()\n",
    "p = figure()\n",
    "\n",
    "bnum = 11\n",
    "\n",
    "key = attack.knownKey()\n",
    "data = attack.getStatistics().diffs[bnum]\n",
    "xr = range(0, len(data[0]))\n",
    "\n",
    "for v in range(0, 256):\n",
    "    p.line(xr, data[v], line_color='green')\n",
    "\n",
    "p.line(xr, data[key[bnum]], line_color='red')\n",
    "show(p)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You should see a graph of red and green in time (samples). In red is the correlation of the correct subkey for the first byte, while the rest are in green. You can use this graph to help fine-tune the windowing of the data."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conclusion"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Attacking hardware crypto is similar to any other DPA style attack. In this example we have concentrated on the standard \"Last Round State\" to break a real hardware accelerator."
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
